提出技術資料
共有:閲覧用シートの高速化・保守アプローチ案
(※これは「ボイスまとめ閲覧用シートのパフォーマンス改善案(bom付UTF8).txt」という提案した際の添付ファイルの中身である)
このドキュメントでは、データの増大に伴うスプレッドシートの負荷を
「関数の集約(MAP関数)」と「構造の同期(GAS)」で解決する案をまとめています。
[目次]
01. 概要:なぜ数式を1つに絞ると軽くなるのか
02. 軽量重視:数式1つで完結させる「1発パターン」
03. 管理重視:GASによる「構造同期パターン」
04. 補足:導入時の手順とバックアップについて
01. 概要:なぜ数式を1つに絞ると軽くなるのか
現状の「全セルへの数式配置」を、MAP関数等による「配列処理」に置き換えることで、再計算の負荷を最小化します。
軽量重視の「関数一発型」と、拡張性重視の「GAS同期型」の2種類をまとめています。
※現在の数式を上書きするため、念のためバックアップを取った上での検証を推奨します。
02. 軽量重視:数式1つで完結させる「1発パターン」
メンテナンス性は2つ目に譲りますが、シートに数式を1つ貼るだけで完結します。(軽量重視・スマホ対応可)
・技ボイス閲覧用シートV4用
=MAP(UNIQUE
(FILTER (表_統合シート[名前], LEN(TRIM(表_統合シート[名前]))>0)),
LAMBDA(
name,
IF(
name="", "",
{
XLOOKUP(name, '選手マスタV4'!$C:$C, '選手マスタV4'!$B:$B, "未登録"),
name,
XLOOKUP(name, '選手マスタV4'!$C:$C, '選手マスタV4'!$D:$G, "未登録")
}
)
)
)
これを「技ボイス閲覧用シートV4」の「B5121セル」か、全キャラデータでやる場合は非表示になっている「B4セル」に入れます。
1発で全部埋まります。
ただ他の中身(関数を入れるセルであるB5121セルか、B4セルから、最も右下のセルまで)を空にしてから実行してください。
・技名からキャラ名閲覧シートV4
=MAP(
'技マスタV4'!B22:B,
'技マスタV4'!C22:C,
'技マスタV4'!D22:D,
'技マスタV4'!F22:F,
LAMBDA(
v_id, v_kbn1, v_kbn2, v_name,
IF(
v_id="",
"",
{
v_id,
v_kbn1,
v_kbn2,
v_name,
IFERROR(
TEXTJOIN(
"、",
TRUE,
FILTER(
'統合シートV4'!$C:$C,
'統合シートV4'!$D:$D=v_name,
TRIM('統合シートV4'!$E:$E)="あり"
)
),
""
)
}
)
)
)
これは「技名からキャラ名閲覧シートV4」の、「B4セル」に入れれば一発です。
ID0001~0019が使われた場合や、今後技が増えた場合にもこれで対応します。
こちらも、他の中身(B4セルから、最も右下のセルまで)を空にしてから実行してください。
・技ボイス閲覧用シートV4用
・技名からキャラ名閲覧シートV4
この2シートに対して、
各セルごとの「=◯◯」の関数や数式、別シートの値参照をしていた部分が、これ1個で済むので、関数量が非常に減り閲覧用シートのパフォーマンスの改善が期待できます。
次に紹介するものより高パフォーマンスが期待できるのですが、
もし何かの修正が必要になった際には、複雑化しているので少しわかりづらく、手入れがしにくいという面がデメリットです。
03. 管理重視:GASによる「構造同期パターン」
こちらは「数式の配置をプログラムに任せる」方法です。(管理・メンテナンス性重視・PC推奨)
GASを使う想定のため、スマホからは実行できませんが、
将来のレイアウト変更にもスクリプト側の修正で柔軟に対応できる構造のため、長期的な運用に向いています。
これは『正しい数式をGASに覚えさせておいて、ボタン一つで複数箇所の特定のセルに関数を実行させる』というアプローチになっています。
もしもGASの中身を手動で行う場合は下記のようになります。
手動実行は想定していませんが、中身が分からないと懸念材料になるため、一応念の為の、中身はこれを1度に自動実行するものというバラした紹介です。
(懸念にならないような説明部分で書いているだけなので、実際に大事なのは後述するGASのスクリプトです。)
手動でやる場合の手順(GASの実質的な処理の中身) ※改行が多くなるので入れ子部分もまとめて1行にしています、すみません…
- 技ボイス閲覧シートV4の、B4セルから最も右下のセルまで全て空にする
- 技ボイス閲覧シートV4の、B5121セルに、 =MAP(C5121:C, LAMBDA(name, IF(name="", "", XLOOKUP(name, '選手マスタV4'!$C:$C,'選手マスタV4'!$B:$B, "未登録"))))
- 技ボイス閲覧シートV4の、C5121セルに、 =UNIQUE(FILTER(表_統合シート[名前], LEN(TRIM(表_統合シート[名前]))>0))
- 技ボイス閲覧シートV4の、D5121セルに、 =MAP(C5121:C, LAMBDA(name, IF(name="", "", XLOOKUP(name, '選手マスタV4'!$C:$C,'選手マスタV4'!$D:$G, "未登録")))) ※4列処理
- 技ボイス閲覧シートV4の、H5121セルに、 =MAP(B5121:B, C5121:C, LAMBDA(id, name, IF(name="", "", LET(hz,IFNA(FILTER(表_統合シート[必殺技], (表_統合シート[ID]=id) * (表_統合シート[名前]=name) * (表_統合シート[ボイス有無]="あり")), ""), joined, TEXTJOIN("、", TRUE, hz), IF(joined="", "[技ボイス未発見]", joined)))))
- 技ボイス閲覧シートV4の、I5121セルに、 =MAP(C5121:C, LAMBDA(name, IF(name="", "", IFERROR(XLOOKUP(name, 表_選手マスター[名前], 表_選手マスター[備考], ""), ""))))
- 技名からキャラ名閲覧シートV4の、B4セルから最も右下のセルまで全て空にする
- 技名からキャラ名閲覧シートV4の、B4セルに =MAP('技マスタV4'!B22:B, '技マスタV4'!C22:C, '技マスタV4'!D22:D, '技マスタV4'!F22:F, LAMBDA(v_id, v_kbn1, v_kbn2, v_name, IF(v_id="", "", {v_id, v_kbn1, v_kbn2, v_name})))
- 技名からキャラ名閲覧シートV4の、F4セルに、 =MAP(E4:E, LAMBDA(v_name, IF(v_name="", "", IFERROR(TEXTJOIN("、", TRUE, FILTER('統合シートV4'!$C:$C, '統合シートV4'!$D:$D=v_name, TRIM('統合シートV4'!$E:$E)="あり")), ""))))
これで「技ボイス閲覧用シートV4用」が、各列ごとに5121行目/4行目から下まで基本それぞれ1つの関数でできるので軽くなります。
こちらは上記のように、細かい関数を入れているため手間があるように思えますが…、実はこれを下記GASスクリプトで1発でやれます
長期的に見た場合は、1つ目の例よりもメンテナンス性・拡張性はこちらの方が高くなります。
上記の手動手順はGASの中身処理というだけですので…
1~9の手順を、GASで1発でやるスクリプトがこちらになります
-------[↓ここからGASスクリプト↓]-------
/**
* 閲覧用シートの構造を最新の状態に同期(最適化)する関数
* 各シートの設定値を書き換えるだけで、レイアウト変更にも対応可能です。
*/
function syncViewSheetStructures() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
// =======================================================
// 1. 【技ボイス閲覧シートV4】の設定と実行
// =======================================================
const sheetV4 = ss.getSheetByName("技ボイス閲覧シートV4");
if (sheetV4) {
// --- 設定エリア ---
const START_ROW = 5121;
const COL = {
ID: "B",
NAME: "C",
DATA: "D", // D:G(性別・属性・Pos・ビルド)
WAZA: "H",
MEMO: "I"
};
// -----------------
// 旧データのクリア(B列からI列の、開始行以降をすべて削除)
const lastRow = sheetV4.getMaxRows();
sheetV4.getRange(`${COL.ID}${START_ROW}:${COL.MEMO}${lastRow}`).clearContent();
// 各数式の定義
const formulasV4 = [
// B列: ID取得
{
range: `${COL.ID}${START_ROW}`,
formula: `=MAP(${COL.NAME}${START_ROW}:${COL.NAME}, LAMBDA(name, IF(name="", "", XLOOKUP(name, '選手マスタV4'!$C:$C, '選手マスタV4'!$B:$B, "未登録"))))`
},
// C列: 名前抽出(起点)
{
range: `${COL.NAME}${START_ROW}`,
formula: `=UNIQUE(FILTER(表_統合シート[名前], LEN(TRIM(表_統合シート[名前]))>0))`
},
// D列: 基本情報4列一括(D:G)
{
range: `${COL.DATA}${START_ROW}`,
formula: `=MAP(${COL.NAME}${START_ROW}:${COL.NAME}, LAMBDA(name, IF(name="", "", XLOOKUP(name, '選手マスタV4'!$C:$C, '選手マスタV4'!$D:$G, "未登録"))))`
},
// H列: 必殺技合体
{
range: `${COL.WAZA}${START_ROW}`,
formula: `=MAP(${COL.ID}${START_ROW}:${COL.ID}, ${COL.NAME}${START_ROW}:${COL.NAME}, LAMBDA(id, name, IF(name="", "", LET(hz, IFNA(FILTER(表_統合シート[必殺技], (表_統合シート[ID]=id) * (表_統合シート[名前]=name) * (表_統合シート[ボイス有無]="あり")), ""), joined, TEXTJOIN("、", TRUE, hz), IF(joined="", "[技ボイス未発見]", joined)))))`
},
// I列: 備考
{
range: `${COL.MEMO}${START_ROW}`,
formula: `=MAP(${COL.NAME}${START_ROW}:${COL.NAME}, LAMBDA(name, IF(name="", "", IFERROR(XLOOKUP(name, 表_選手マスター[名前], 表_選手マスター[備考], ""), ""))))`
}
];
// 実行:数式をセット
formulasV4.forEach(f => {
sheetV4.getRange(f.range).setFormula(f.formula);
});
console.log("技ボイス閲覧シートV4の同期完了");
}
// =======================================================
// 2. 【技名からキャラ名閲覧シートV4】の設定と実行
// =======================================================
const sheetWaza = ss.getSheetByName("技名からキャラ名閲覧シートV4");
if (sheetWaza) {
// --- 設定エリア ---
const START_ROW = 4;
const COL = {
INFO: "B", // B:E(ID・区分1・区分2・技名)
NAME: "E", // 検索キーとなる技名
CHARA: "F" // ボイス付きキャラ連結
};
// -----------------
// 旧データのクリア(B列からF列)
const lastRow = sheetWaza.getMaxRows();
sheetWaza.getRange(`${COL.INFO}${START_ROW}:${COL.CHARA}${lastRow}`).clearContent();
// 各数式の定義
const formulasWaza = [
// B列: 技情報4列一括(B:E)
{
range: `${COL.INFO}${START_ROW}`,
formula: `=MAP('技マスタV4'!B22:B, '技マスタV4'!C22:C, '技マスタV4'!D22:D, '技マスタV4'!F22:F, LAMBDA(v_id, v_kbn1, v_kbn2, v_name, IF(v_id="", "", {v_id, v_kbn1, v_kbn2, v_name})))`
},
// F列: ボイス付きキャラ連結
{
range: `${COL.CHARA}${START_ROW}`,
formula: `=MAP(${COL.NAME}${START_ROW}:${COL.NAME}, LAMBDA(v_name, IF(v_name="", "", IFERROR(TEXTJOIN("、", TRUE, FILTER('統合シートV4'!$C:$C, '統合シートV4'!$D:$D=v_name, TRIM('統合シートV4'!$E:$E)="あり")), ""))))`
}
];
// 実行:数式をセット
formulasWaza.forEach(f => {
sheetWaza.getRange(f.range).setFormula(f.formula);
});
console.log("技名からキャラ名閲覧シートV4の同期完了");
}
SpreadsheetApp.getUi().alert("各閲覧用シートを最新の構造に同期しました!");
}
/**
* 【管理者用】メニューの追加設定
* 必要に応じて機能を有効化してください。
* * [有効化の手順]
* 1. 以下のコメントアウトを外して上書き保存します。
* 2. スプレッドシートをブラウザで更新(F5)すると、上部メニューに「? 構造同期ツール」が追加されます。
*
* * [運用上の注意]
* ・特定のメールアドレスの方のみに制限する機能は、
* スクリプトコード(GAS)の共有しやすさを優先して実装していません。
* ・共有範囲に応じて、本機能を有効にして運用するかは管理者様の判断にお任せ致します。
* ・有効化した場合、編集権限を持つユーザーは誰でも実行可能になります。
*/
/*
function onOpen() {
const ui = SpreadsheetApp.getUi();
ui.createMenu('? 構造同期ツール')
.addItem('閲覧シートの同期を実行', 'syncViewSheetStructures')
.addToUi();
}
*/
-------[↑ここまでGASスクリプト↑]-------
こちら2点目の案の利点は、
もしシートの間に列を入れる修正や、対象となるスプレッドシートがV5に今後変わっても、GASスクリプト側の管理・変更でメンテナンス・修正が簡単という点です。
もし権限のある方がスマホからではなく、PCから実行できる場合は、こちらの方が可読性も高くオススメです。
04. 補足:導入時の手順とバックアップについて
どちらの方法も、これまでの『全セルに数式が入っている状態』を劇的に解消し、ファイルの読み込みを軽くできるはずです。
また、どちらの場合も処理の都合で、"処理先にデータが入っていると上手く実行しない"ため、一度処理先として参照される先の中身を消してから実行する必要があります。
(2つ目のGASスクリプトの実行の場合は、中身を消す処理も先に入っているので、自分で予め消さずともスクリプト1発実行するだけで、今と同じ中身が構築されます)
検討の際は、念のため、現在のファイルをコピーしてバックアップを取った上でお試しください。
一つのアイデアとしてご検討いただけますと幸いです。(※ただのアイデアなので、現状のままでも全く問題ありません。)
一ユーザーとして、皆様の検証活動を応援しております。
(※上記までが「ボイスまとめ閲覧用シートのパフォーマンス改善案(bom付UTF8).txt」という提案した際の添付ファイルの中身である)
重要:著作権保護および利用拒否の宣言
- 権利の帰属: 本著作物(関数、アルゴリズム、ロジック、解説文を含む)の一切の権利は制作者に帰属します。
- 利用禁止: 営利・非営利を問わず、本著作物の全部または一部を、権利者の承諾なく複製、転載、改変、配布、および外部サービス等へ組み込んで利用することを固く禁じます。
- 裁定制度への対応: 本著作物は、令和8年度(2026年度)施行の「未管理著作物裁定制度」における利用を、あらかじめ明確に拒絶します。
- 意思表明: 連絡先の不記載は権利の放棄を意味しません。本記述をもって、あらゆる第三者による無断利用に対する「拒絶の意思」とみなします。
- 許諾の撤回: 権利者は、信義則に反する行為が認められた場合、付与した利用許諾をいつでも即時に撤回する権利を有します。
(※以下は関数案を採用した「めがね星人」に2026/03/05 17:08に、送った「関数排除の復元手順.txt」という添付ファイルの中身である)
関数排除の復元手順
私の関数を排除し、元の状態に戻す方法をまとめました。 ============================ 【技ボイス閲覧シート】・B4セル(ID) =IFERROR(INDEX(表_選手マスター[ID], MATCH($C5121, 表_選手マスター[名前], 0)), "")・C4セル(名前)=UNIQUE( FILTER( 表_統合シート[名前], LEN(TRIM(表_統合シート[名前]))>0 ) )・D4セル(性別) =IFERROR(INDEX('選手マスタV4'!$D$3:$D$2975, MATCH($C5121, '選手マスタV4'!$C$3:$C$2975, 0)), "") ・E4セル(属性) =IFERROR(INDEX('選手マスタV3'!$E$3:$E$2975, MATCH($C5121, '選手マスタV3'!$C$3:$C$2975, 0)), "") ・F4セル(Pos) =IFERROR(INDEX('選手マスタV3'!$F$3:$F$2975, MATCH($C5121, '選手マスタV3'!$C$3:$C$2975, 0)), "") ・G4セル(ビルド) =IFERROR(INDEX('選手マスタV3'!$G$3:$G$2975, MATCH($C5121, '選手マスタV3'!$C$3:$C$2975, 0)), "")・H4セル(ボイスあり必殺技)=IF( C5121="", "", LET( id, B5121, name, C5121, hz, IFNA( FILTER( 表_統合シート[必殺技], (表_統合シート[ID]=id) * (表_統合シート[名前]=name) * (表_統合シート[ボイス有無]="あり") ), "" ), joined, TEXTJOIN("、", TRUE, hz), IF( joined="", "[技ボイス未発見]", joined ) ) )・I6セル(備考) =IFERROR(INDEX(表_選手マスター[備考], MATCH($C5121, 表_選手マスター[名前], 0)), "")=========================================== 【技ボイス閲覧シート】・B4セル(技ID) ='技マスタV4'!B22 ・C4セル(必殺技区分1) ='技マスタV4'!C22 ・D4セル(必殺技区分2) ='技マスタV4'!D22 ・E4セル(必殺技名) ='技マスタV4'!F22・F4セル(ボイス付きで使えるキャラ)=IFERROR( TEXTJOIN("、", TRUE, FILTER( '統合シートV4'!C:C, '統合シートV4'!D:D=E4, TRIM('統合シートV4'!E:E)="あり" ) ), "" )・G4セル(備考) ※関数・数式なしの空欄でした ============================================== 【復元方法】 1. 上記関数をそれぞれのセルに入れ直す 2. 4行目全体か、適用した4行目セルの範囲選択 3. 一番下までドラッグ 4. 元の状態に戻し、私の提供は排除されます(お手数ですが、これによりクレジットから私の名前も削除してください) 以上の工程で復元可能です。おおよそ5分あれば完了します。 ※本手順(txt)の著作権は放棄します。自由に使用・改変可。 ※2/17元状態を解析し、検証済み(V3→V4時のバックアップで確認)
(※上記までが関数案を採用した「めがね星人」に2026/03/05 17:08に、送った「関数排除の復元手順.txt」という添付ファイルの中身である)
本記録の目的と権利関係
本ケーススタディは、善意で提供した技術成果物が、信頼関係の破綻後も制作者(権利者)の意向を無視して利用され続けている事実を記録することを目的としている。
提示している「ボイスまとめ閲覧用シートのパフォーマンス改善案(bom付UTF8).txt」の著作権は制作者にある。権利者は2026年3月2日付で、対象者に対して明確に「使用許諾の撤回」と「現状復旧」を要求しており、現時点でこの技術が稼働し続けている状態は、権利者の意図に反するものである。
制作者の技術によってスプレッドシートが劇的に軽量化され、利用者がその恩恵(時短・効率化)を享受しているのであれば、許諾撤回後の継続利用は、他者の財産(著作物)を無断で使用して利益を得る「不当利得」に近い状態といえる。
まとめ
著作権の所在について
「特に条件を定めず」提供したとしても、制作者が作成したコードやドキュメントの著作権は、明示的に放棄していない限り、依然として制作者に帰属する。
「黙示の許諾」の範囲について
無条件で提供した以上、利用者には「それを使う権利(ライセンス)」が黙示的に与えられたとみなされる。ただし、これは「権利の譲渡」ではない。明確な契約書がない場合であっても、制作者は利用者に対して利用を「許諾(ライセンス)」した状態にあるにすぎず、信義則を裏切るような行為があった場合には、「この信頼関係が維持されることを前提とした許諾だった」と主張できる。信頼関係が壊れた以上、許諾を撤回し「今後は著作物(関数・ロジック)を使用しないでください」と要求することは、正当な権利行使の範囲内である。
「アイデアに著作権はない」という主張の誤用について
そのアイデアを形にするために、制作者がどれだけ具体的な創作(記述・構築)を介在させたかが重要な判断基準となる。利用者が制作者の「表現(コードや構成)」をそのまま使用しているのであれば、「アイデアに著作権はない」という主張は的外れである。
制作者が提供したものは、単なる「便利な数式のメモ」ではなく、「データ構造の分析、ボトルネックの特定、そして解決のための高度なロジック設計」という一連の知的成果物(パッケージ)とみなされる。具体的には以下の点が創作性の根拠となる。
- 創作性の認定: 12,000個の関数を2個に集約し、MAP・LAMBDAを駆使した複雑なエラーハンドリングを含む「スピル数式」は、単なる計算式ではなく「プログラムのソースコード」と同等とみなされる。日本の裁判例においても、プログラムの著作物性は「具体的な記述(コード)」に認められており、制作者の関数の文字列そのものが、著作権法上の「プログラムの著作物」として保護対象となり得る。
- 選択と配列: どの関数を組み合わせ、どのようなロジックで最適化するかというプロセスには、制作者の個性が強く反映される。
- ドキュメントの付随: 導入手順、分析結果、GAS版との比較を含む「パッケージ」として提供している点も重要である。これは編集著作物としての著作権が認められるため、利用者がそれを読んで採用している時点で、制作者の著作物を利用していることになる。
まとめると、「スプレッドシートを軽くする」というアイデア自体は誰でも自由に発想できる。しかし制作者が検証・最適化した「特定の関数構成(文字列・ロジック)」は著作物であり、引き続き使用したい場合には制作者の許諾が必要である。
秘密保持(NDA)について
「秘密として扱う」という約束(明示的・黙示的)のもとで共有した技術情報を第三者に漏洩し、それが悪意ある攻撃の手段として利用された。ファンネル1号(酢味噌/hinata_usa)はNDA違反を犯している。